﻿using Common.Infrastructure;
using Common.Infrastructure.Logs;
using Common.Infrastructure.Service;
using Common.Infrastructure.Utils;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Common.AspNetCore
{
    public class ApiSyncController : ApiControllerBase
    {
        public ApiSyncController(IServiceProvider provider) : base(provider)
        {
        }

        public async Task<ApiActionResult<bool>> SafeExecuteBySyncAsync(SyncParam syncParam, Func<SyncResult, Task<bool>> func)
        {
            ApiActionResult<bool> ret = new ApiActionResult<bool>();
            SyncResult param = new SyncResult();
            DateTime startTime = DateTime.Now;

            try
            {
                bool checkstate = CheckSync(syncParam);
                if (!checkstate)
                {
                    ret.Data = await func(param);
                    DoAfterSafeExecute();
                }
            }
            catch (CodeException ex)
            {
                var temp = GetErrorMsg(ex, out string trace);
                ret.Messages.Add(new ApiActionMessage() { MessageType = EFMessageType.Error, Message = temp, StackTrace = trace, Code = ex.Code });
            }
            catch (Exception ex)
            {
                var temp = GetErrorMsg(ex, out string trace);
                ret.Messages.Add(new ApiActionMessage() { MessageType = EFMessageType.Error, Message = temp, StackTrace = trace, });
            }

            ret.IsSuccess = !ret.Messages.Any(t => t.MessageType == EFMessageType.Error);
            LibMessageUtils.MessageToActionResult<bool>(this.Provider, ret);
            if (!ret.IsSuccess && string.IsNullOrEmpty(ret.Code))
            {
                ret.Code = "-1";
            }

            AddSyncLogAndUnLock(startTime, param, syncParam);
            return ret;
        }

        public ApiActionResult<bool> SafeExecuteBySync(SyncParam syncParam, Func<SyncResult, bool> func)
        {
            ApiActionResult<bool> ret = new ApiActionResult<bool>();

            SyncResult param = new SyncResult();
            DateTime startTime = DateTime.Now;

            try
            {
                bool checkstate = CheckSync(syncParam);
                if (!checkstate)
                {
                    ret.Data = func(param);
                    DoAfterSafeExecute();
                }
            }
            catch (CodeException ex)
            {
                var temp = GetErrorMsg(ex, out string trace);
                ret.Messages.Add(new ApiActionMessage() { MessageType = EFMessageType.Error, Message = temp, StackTrace = trace, Code = ex.Code });
            }
            catch (Exception ex)
            {
                var temp = GetErrorMsg(ex, out string trace);
                ret.Messages.Add(new ApiActionMessage() { MessageType = EFMessageType.Error, Message = temp, StackTrace = trace, });
            }

            ret.IsSuccess = !ret.Messages.Any(t => t.MessageType == EFMessageType.Error);
            LibMessageUtils.MessageToActionResult<bool>(this.Provider, ret);
            if (!ret.IsSuccess && string.IsNullOrEmpty(ret.Code))
            {
                ret.Code = "-1";
            }

            AddSyncLogAndUnLock(startTime, param, syncParam);
            return ret;
        }

        private void AddSyncLogAndUnLock(DateTime startTime, SyncResult result, SyncParam syncParam)
        {
            try
            {
                var key = this.GetSyncKey(syncParam);
                LibRedisCacheUtils.Delete(this.Provider, key);
            }
            catch
            {
            }

            var cacheService = this.Provider.GetService<IComonCacheService>();
            SyncLogModel syncLog = new SyncLogModel()
            {
                SyncId = syncParam.Id,
                ExeSecond = (int)(DateTime.Now - startTime).TotalSeconds,
                AddC = result.AddCount,
                UpdateC = result.UpdateCount,
                Msg = result.Message,
                DelC = result.DeleteCount,
                Api = this.HttpContext.Request.Path,
                ApiKey = cacheService.GetApiKey(),
            }; 
            _ = WebApiUtils.PostByResponse($"{cacheService.GetGroupUrl()}/api/SyncLog/AddSyncLog", syncLog); 
        }

        private bool CheckSync(SyncParam syncParam)
        {
            var key = GetSyncKey(syncParam);
            var ret = LibRedisCacheUtils.Exists(this.Provider, key);
            if (ret)
            {
                return ret;
            }

            var locks = syncParam.LockSecond == 0 ? 120 : syncParam.LockSecond;
            LibRedisCacheUtils.Set(this.Provider, key, "true", new TimeSpan(0, 0, locks));
            return false;
        }

        private string GetSyncKey(SyncParam syncParam)
        {
            return $"sys_sync_{syncParam.Id}";
        }
    }
}
